package service

import (
	"context"
	"github.com/gogf/gf/v2/encoding/gjson"
	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/text/gstr"
	"github.com/gogf/gf/v2/util/gconv"
	"net/http"
	"strings"
	"websocket/internal/consts"
	"websocket/internal/model"
	"websocket/utility"
)

type (
	// sMiddleware is service struct of module Middleware.
	sMiddleware struct{}
)

var (
	// insMiddleware is the instance of service Middleware.
	insMiddleware = sMiddleware{}
)

// Middleware returns the interface of Middleware service.
func Middleware() *sMiddleware {
	return &insMiddleware
}

// Ctx injects custom business context variable into context of current request.
func (s *sMiddleware) Ctx(r *ghttp.Request) {
	r.Middleware.Next()
}

// CORS allows Cross-origin resource sharing.
func (s *sMiddleware) CORS(r *ghttp.Request) {
	r.Response.CORSDefault()
	r.Middleware.Next()
}

//TryParseToken token试解析
func (s *sMiddleware) TryParseToken(r *ghttp.Request) {
	var (
		auth    *model.ContextAuth
		parseOk bool
	)
	_ = g.Try(r.Context(), func(ctx context.Context) {
		authHeader := r.GetHeader("Authorization")
		if authHeader != "" {
			parts := strings.SplitN(authHeader, " ", 2)
			if len(parts) == 2 && parts[0] == "Bearer" && parts[1] != "" && gstr.ToLower(parts[1]) != "null" {
				//默认走车企的秘钥解析 后续根据角色判定使用解析的秘钥
				//role:=r.GetHeader("Role")
				data, err := utility.Auth.DecryptData(r.Context(), parts[1])
				if err == nil && data != "" {
					err = gjson.DecodeTo(data, &auth)
					if err == nil {
						parseOk = true
					}
				}
			}
		}
	})
	if parseOk == true && auth != nil {
		//解析token成功 设置请求时间并初始化上下文认证信息
		Context().InitAuth(r, auth)
		Context().GetLogger(r.Context()).Author = auth
	}
	r.Middleware.Next()
}

//Auth 角色登录认证
func (s *sMiddleware) Auth(r *ghttp.Request) {
	reqCtx := Context().GetAuth(r.Context())
	if reqCtx == nil {
		r.Response.WriteStatus(http.StatusForbidden)
		return
	}
	r.Middleware.Next()
}

func (s *sMiddleware) Logger(r *ghttp.Request) {
	Context().InitLogger(r, &model.ContextLogger{
		TraceId:       gctx.CtxId(r.Context()),
		RequestBody:   gconv.String(r.GetBody()),
		RequestParams: r.GetMap(),
		XRealIP:       r.GetHeader("X-Real-IP"),
		ClientIP:      r.GetClientIp(),
		RequestUrl:    r.RequestURI,
		RequestUri:    r.Router.Uri,
		RequestMethod: r.Method,
		RequestTime:   gtime.Now(),
		FinishTime:    nil,
		RunTime:       "0",
		Author:        nil,
	})
	r.Middleware.Next()
	//logger := Context().GetLogger(r.Context())
	//根据method将log入库
}

func (s *sMiddleware) Response(r *ghttp.Request) {
	r.Middleware.Next()
	//固化执行完成时间 计算运行时长
	logger := Context().GetLogger(r.Context())
	logger.FinishTime = gtime.Now()
	logger.RunTime, _ = utility.Math.Sub(r.Context(), gconv.String(logger.FinishTime.TimestampMilli()), gconv.String(logger.RequestTime.TimestampMilli()))

	var (
		err           = r.GetError()
		code          = gcode.CodeOK.Code()
		printErrLoger = false
		responseBody  = CustomHandlerResponse{
			Code:           gcode.CodeOK.Code(),
			Message:        "success",
			RealityMessage: "success",
			Data:           r.GetHandlerResponse(),
		}
	)
	if err != nil {
		responseBody.RealityMessage = err.Error()
		// 异常时含有异常错误文本 - panic[orm,redis,plug...]
		if r.Response.BufferLength() > 0 {
			r.Response.ClearBuffer()
			responseBody.Code = consts.StatusInternalServerError
			responseBody.Message = "服务器开小差了[" + gctx.CtxId(r.Context()) + "]"
			//panic错误-输出栈堆
			printErrLoger = true
		} else {
			//置换错误码
			responseBody.Code = gerror.Code(err).Code()
			//置换错误消息
			//内部错误-输出栈堆
			if gerror.Code(r.GetError()).Code() == gcode.CodeValidationFailed.Code() {
				//入参校验错误
				responseBody.Message = err.Error()
			} else {
				if gerror.Code(r.GetError()).Code() <= gcode.CodeInvalidRequest.Code() && gerror.Code(r.GetError()).Code() != gcode.CodeOK.Code() {
					responseBody.Message = "服务器开小差了[" + gctx.CtxId(r.Context()) + "]"
					printErrLoger = true
				} else {
					responseBody.Message = err.Error()
				}
			}

			//非成功状态码强制转换
			if code == gcode.CodeNil.Code() {
				responseBody.Code = gcode.CodeInternalError.Code()
			}
			//参数校验失败强制转换
			if code == gcode.CodeValidationFailed.Code() {
				responseBody.Code = consts.StatusCustomNotApproved
			}
		}
	} else {
		//判断middleware是否提前终止执行流程
		if r.Response.Status > 0 && r.Response.Status != http.StatusOK {
			r.Response.ClearBuffer()
			responseBody.Message = consts.StatusHttp().Text(r.Response.Status)
			switch r.Response.Status {
			case http.StatusNotFound:
				code = gcode.CodeNotFound.Code()
			case http.StatusForbidden:
				code = gcode.CodeNotAuthorized.Code()
			default:
				code = gcode.CodeUnknown.Code()
			}
		}
	}
	logger.ResponseBody = gconv.Map(responseBody)
	r.Response.WriteJson(responseBody)
	if printErrLoger {
		utility.Common.OutputLog2DayByGroup(r.Context(), "errors", logger, gerror.Stack(r.GetError()))
	}
}

type CustomHandlerResponse struct {
	Code           int         `json:"code"  `
	Message        string      `json:"message"`
	RealityMessage string      `json:"-" p:"reality_message"`
	Data           interface{} `json:"data"`
}
